package com.dev.cmielke.generator;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.apache.commons.lang.StringEscapeUtils;
import org.apache.log4j.Logger;

import com.dev.cmielke.beans.BookType;
import com.dev.cmielke.beans.PerryRhodanBook;
import com.dev.cmielke.util.ApplicationContants;
import com.dev.cmielke.util.LoadWriteUtils;

public class HTMLGenerator {
	private final PerryRhodanBook book;
	private final String htmlTemplate;
	private final ArrayList<String> htmlPages;

	private enum HTMLWriteMode {
		SINGLE_FILE, MULTI_FILE
	};

	private static final Logger log = Logger.getLogger(HTMLGenerator.class);

	public HTMLGenerator(PerryRhodanBook book) {
		this.book = book;
		this.htmlTemplate = LoadWriteUtils.getHTMLTemplate();
		this.htmlPages = new ArrayList<String>();
	}

	public void generateEPub() {
		log.trace("> generateEPub...");
		replacePlaceholders(HTMLWriteMode.MULTI_FILE);
		processCover();
		writeHTML();
		log.trace("< generateEPub");
	}

	private void replacePlaceholders(HTMLWriteMode mode) {
		log.trace("> Replacing Placeholders...");
		switch (mode) {
		case SINGLE_FILE: {
			generateSingleHTMLFile();
			break;
		}
		case MULTI_FILE: {
			generateMultiHTMLFiles();
			break;
		}
		}
		log.trace("< Replacing Placeholders");
	}

	private void generateMultiHTMLFiles() {
		log.trace("> generateMultiHTMLFiles...");

		if(getBook().containsIntroduction()) {
			log.debug("Generating file for introduction");
			String copy = getHtmlTemplate().replace("%TITLE%", getPlainTitle());
			StringBuilder buffer = new StringBuilder();
			if(getBook().getType()==BookType.HEFTROMAM) {
				buffer.append(getFormatedBookNumber()).append("\n");
			}
			buffer.append(getFormatedTitle()).append("\n");
			buffer.append(getFormatedSubtitle()).append("\n");
			if(getBook().containsAuthors()) buffer.append(getFormatedAuthors()).append("\n");
			buffer.append(getFormatedIntroduction()).append("\n");
			if(getBook().containsCharacters()) buffer.append(getFormatedCharacters()).append("\n");
			copy = copy.replace("%TEXT%", buffer.toString());
			getHtmlPages().add(copy);
			log.trace("introduction page complete!");
		}

		log.debug("Generating files for every chapter");
		for (int chapter = 0; chapter < getBook().getChapterCount(); chapter++) {
			log.trace("> Processing Chapter [" + (chapter + 1) + "]");
			String copy = getHtmlTemplate().replace("%TITLE%", getPlainTitle());

			StringBuffer buffer = new StringBuffer();
			String temp = getFormatedChapterPreface(chapter);

			if (!temp.isEmpty()) {
				buffer.append(temp).append("\n");
			}
			buffer.append(getFormatedChapterText(chapter)).append("\n");

			copy = copy.replace("%TEXT%", buffer.toString());
			getHtmlPages().add(copy);
			log.trace("< Chapter [" + (chapter + 1) + "] complete.");
		}
		log.debug("chapter complete!");
		log.trace("< generateMultiHTMLFiles");
	}

	private void generateSingleHTMLFile() {
		log.trace("> generateSingleHTMLFile...");
		String copy = getHtmlTemplate().replace("%TITLE%", getPlainTitle());

		StringBuffer buffer = new StringBuffer();
		buffer.append(getFormatedBookNumber()).append("\n");
		buffer.append(getFormatedTitle()).append("\n");
		buffer.append(getFormatedSubtitle()).append("\n");
		if(getBook().containsAuthors()) buffer.append(getFormatedAuthors()).append("\n");
		buffer.append(getFormatedIntroduction()).append("\n");
		if(getBook().containsCharacters()) buffer.append(getFormatedCharacters()).append("\n");

		for (int index = 0; index < getBook().getChapterCount(); index++) {
			log.trace("> Processing Chapter [" + (index + 1) + "]");
			String temp = getFormatedChapterPreface(index);

			if (!temp.isEmpty()) {
				buffer.append(temp).append("\n");
			}
			buffer.append(getFormatedChapterText(index)).append("\n");
			log.trace("< Chapter [" + (index + 1) + "] complete.");
		}

		copy = copy.replace("%TEXT%", buffer.toString());
		getHtmlPages().add(copy);

		log.trace("< generateSingleHTMLFile");
	}

	private String getPlainTitle() {
		switch(getBook().getType()) {
		case HEFTROMAM:
			return "Band " + getBook().getBookNumber() + " - " + StringEscapeUtils.escapeHtml(getBook().getTitle());
		case SILBERBAND:
			return "Silberband " + getBook().getBookNumber() + " - " + StringEscapeUtils.escapeHtml(getBook().getSubtitle());
		default:
			return StringEscapeUtils.escapeHtml(getBook().getTitle());
		}
	}

	private String getFormatedTitle() {	//TODO
		String title = "<h1 class=\"bookTitle\">" + StringEscapeUtils.escapeHtml(getBook().getTitle()) + "</h1>";
		return title;
	}

	private String getFormatedBookNumber() {
		String number = "<h2 class=\"bookNumber\">" + "Nr. " + getBook().getBookNumber() + "</h2>";
		return number;
	}

	private String getFormatedSubtitle() {
		String subtitle = "<h2 class=\"subtitle\">" + StringEscapeUtils.escapeHtml(getBook().getSubtitle()) + "</h2>";
		return subtitle;
	}

	private String getFormatedAuthors() {
		String authors = "<h3 class=\"authors\">von " + StringEscapeUtils.escapeHtml(getBook().getAuthors()) + "</h3>";
		return authors;
	}

	private String getFormatedCoverImage() {
		String image = "<img src=\"" + "cover.jpg\" " + "alt=\"Titelbild Band " + getBook().getBookNumber() + "\"/>";
		return image;
	}

	private String getFormatedCharacters() {
		String characters = "<h4>Die Hautpersonen des Romans:</h4>";
		characters += "<ul class=\"characterList\">";
		for (String character : getBook().getCharacters()) {
			String[] asCharacter = character.split("-");
			characters += "<li>";
			for (int index = 0; index < asCharacter.length; index++) {
				if (index == 0) {
					characters += "<strong>" + StringEscapeUtils.escapeHtml(asCharacter[index]) + "</strong>";
					characters += " - ";
				} else {
					characters += StringEscapeUtils.escapeHtml(asCharacter[index]);
				}
			}
			characters += "</li>";
		}
		characters += "</ul>";

		return characters;
	}

	private String getFormatedIntroduction() {
		String bookIntroduction = getBook().getIntroduction().replaceAll("\n", " ");
		bookIntroduction = bookIntroduction.replaceAll("\t", "");
		bookIntroduction = StringEscapeUtils.escapeHtml(bookIntroduction);

		String introduction = "<p class=\"introduction\">" + bookIntroduction + "</p>";
		return introduction;
	}

	private String getFormatedChapterPreface(int chapter) {
		String titel="";
		if(!getBook().hasChapterAPreface(chapter+1)) {
			log.debug("No Preface for Chapter[" + (chapter + 1) + "]");
			return "";
		} else {
			String preface = getBook().getChapterPrefaces().get(Integer.valueOf(chapter + 1)).toString();
			String header = getHeader(preface);
			if(header!=null) {
				preface = preface.replaceAll("%"+header+"%","");
				titel="<h3 class=\"chapterHeader\">" + StringEscapeUtils.escapeHtml(header)+ "</h3>\n";
			}
			return titel + "<p class=\"preface\">" + StringEscapeUtils.escapeHtml(preface) + "</p>";
		}
	}

	private String getFormatedChapterText(int chapter) {
		String chapterText = "";
		try {
			String text = getBook().getChapters().get(chapter).toString();
			String header = getHeader(text);
			
			// Chapter starts with '0', chapterTitle starts with '1'
			String title  = book.getChapterTitle().get(chapter+1); 

			if(header!=null) {
				text = text.replaceAll("%"+header+"%","");
				if(title != null){
					header = header + " " + title;
				}
				chapterText+="<h3 class=\"chapterHeader\">" + StringEscapeUtils.escapeHtml(header)+ "</h3>\n<div class=\"chapterContainer\">\n";
			}
			
			List<String> paragraphs = getParagraphs(text);
			
			for (int index = 0; index < paragraphs.size(); index++) {
				String paragraph = paragraphs.get(index);
				if (paragraph.contains("%E N D E%")) {
					chapterText += "<p class=\"endSeparator\">E N D E</p>\n";
					paragraph = paragraph.replaceAll("%E N D E%", "");
					chapterText += "<p class=\"chapterText\">" + StringEscapeUtils.escapeHtml(paragraph) + "</p>\n";
				}
				else if (paragraph.contains("%E P I L O G%")) {
					if(chapterText.endsWith("<p class=\"separator\">*</p>\n"))
					{
						int start = chapterText.lastIndexOf("<p class=\"separator\">*</p>\n");
						chapterText = chapterText.substring(0, start);
					}
					chapterText += "<p class=\"epilog\">Epilog</p>\n";
					paragraph = paragraph.replaceAll("%E P I L O G%", "");
					chapterText += "<p class=\"chapterText\">" + StringEscapeUtils.escapeHtml(paragraph) + "</p>\n";
				}
				else {
					chapterText += "<p class=\"chapterText\">" + StringEscapeUtils.escapeHtml(paragraph) + "</p>\n";
					if (!((index + 2) >= paragraphs.size())) {
						chapterText += "<p class=\"separator\">*</p>\n";
						
					}
				}
			}

			chapterText += "</div>\n";

		} catch (IndexOutOfBoundsException e) {
			log.error("No such Chapter[" + chapter + "].");
		}
		return chapterText;
	}
	
	private String getHeader(String text) {
		if(text.startsWith("\n\t\t%")) {
			int end=text.indexOf("%", 4);
			return  text.substring(4,end);
		}
		return null;
	}
	static HashMap<String,String> paragraphToken = new HashMap<String,String>();
	static {
		paragraphToken.put("%E N D E%","<p class=\"endSeparator\">E N D E</p>\n");
	}

	private List<String> getParagraphs(String text) {
		ArrayList<String> paragraphs = new ArrayList<String>();
		int startPos = 0;
		int endPos = text.indexOf("%*%");
		while (endPos > 0) {
			paragraphs.add(text.substring(startPos, endPos));
			startPos = endPos + 3;

			endPos = text.indexOf("%*%", startPos);
		}
		endPos = text.length();

		String paragraph = text.substring(startPos, endPos);
		if (paragraph.contains("%E N D E%")) {
			String[] asParagraphs = paragraph.split("%E N D E%");
			for (int index = 0; index < asParagraphs.length; index++) {
				if ((index + 1) >= asParagraphs.length) {
					paragraphs.add("%E N D E%" + asParagraphs[index]);
				} else {
					paragraphs.add(asParagraphs[index]);
				}
			}
		} else {
			paragraphs.add(paragraph);
		}

		return paragraphs;
	}

	private void writeHTML() {
		int count=0;
		log.trace("> writeHTML...");

		if(getBook().containsCover()) {
			log.debug("Writing file for Titelbild");
			LoadWriteUtils.writeHTML(getHtmlPages().get(count++), "title");
		}

		if(getBook().containsIntroduction()) {
			log.debug("Writing file for Introduction");
			LoadWriteUtils.writeHTML(getHtmlPages().get(count++), "introduction");
		}
		for (int chapter=1 ; (count+chapter-1) < getHtmlPages().size(); chapter++) {
			log.debug("Writing file for chapter [" + chapter + "]");
			LoadWriteUtils.writeHTML(getHtmlPages().get(count+chapter-1), 
					LoadWriteUtils.formatChapterNumber(chapter, ApplicationContants.DEFAULT_DIGIT_COUNT));
		}
		log.trace("< writeHTML");
	}

	private void processCover() {
		if (getBook().containsCover()) {
			log.trace("> processCover...");
			saveCoverImageFile();
			generateCoverHTML();
			log.trace("< processCover");
		}
	}

	private void saveCoverImageFile() {
		log.trace("> saveCoverImageFile...");
		LoadWriteUtils.writeCoverImage(getBook().getCoverAsImageObject(), "cover");
		log.trace("< saveCoverImageFile");
	}

	private void generateCoverHTML() {
		log.trace("> writeCoverHTML...");
		String copy = getHtmlTemplate().replace("%TITLE%", getPlainTitle() + " - Titelbild");
		copy = copy.replace("%TEXT%", getFormatedCoverImage());
		getHtmlPages().add(0, copy);
		log.trace("< writeCoverHTML...");
	}

	private PerryRhodanBook getBook() {
		return book;
	}

	private String getHtmlTemplate() {
		return htmlTemplate;
	}

	public ArrayList<String> getHtmlPages() {
		return htmlPages;
	}
}
